"use strict";
// import * as Three from "./three.module.min.js";
// console.log(Three)

/** Object.defineProperty 的简写  */
const obk=Object.defineProperty;
/** document 全局函数的 局部缓存简写 */
const doc:Document=document;
/** body 的局部缓存简写 */
const bod:HTMLElement=doc.body;

const kType=Object.create(null);
      kType.string=1;
      kType.boolean=1;
      kType.number=1;

/**
 * 用户匹配  {{}}
 */   
const BD0=Object.create(null);
      BD0['{']=1,BD0['}']=2;
/**
 * 用于匹配字符串的边界
 * 
 * Boundaries used to match strings
 */    
const BD1=Object.create(null);
      BD1["'"]=1,BD1['"']=2,BD1['`']=3;

/**
 * 用于匹配 各种运算符
 * 
 * Used to match commonly used operators
 * For example: +-*?/><=%:&()[]!
 */    
const BD2=Object.create(null);
      BD2['+']=1,BD2['-']=1,BD2['*']=1,BD2['\\']=1,BD2['%']=1,BD2['?']=1,BD2['>']=1,BD2['<']=1,BD2['=']=1,BD2['&']=1,BD2[':']=1,BD2[',']=1,BD2['!']=1;
      BD2['(']=2,BD2[')']=1;     // 2  方法 () 
      BD2['[']=3,BD2[']']=4;     // 3  data [] 的方法
    
    

/**   以 字母 或 _  或 $ 开头的 方法    */
const regFun=/^([A-z]|\_|\$)+\d*\s*\(.*\)$/;             

/**
 * 获取数据的类型
 * Determine the type of data obtained
 * @param {*} v            any Data
 * @returns {Number}       0:disabled   1: basic( string , number , undefind , null ,boolean )  2: json  3: array 
 */
const GetType =(v:any):number=>{
    const u=undefined;
        if(v===u||v===null)return 1;
    let lx=typeof(v)
        if(kType[lx]===1)return 1;
        if(lx==='object'){
              if(v instanceof Array)return 3;                             // array  
              if(v.$type==='array')return 3;                              // array   
              if(v.constructor&&v.constructor.name ==='Object')return 2;  // json    (通过Object.create(null)创建的对象 无法判定!! )
              if(v.constructor===v.toString)return 2;                     // json    Object.create(null) 创建的json 没有这两个属性
        };
        return 0;
};

/**
 * 从父元素中删除dom 
 * @param {*} dom 
 * @returns 
 */
var DelDom=function(dom:HTMLElement){
    if(!dom)return;
  let p=dom.parentNode;
     if(p)p.removeChild(dom);
      p=null;  
};  

/** 用于生成html的结构配置 */
interface struct{

}

/** 创建 配置 */
interface CFG{
    /** app dom | string id |  结构配置体  */
     el:HTMLElement|'string'|struct,
     /** 样式文本 */
     css:''
     /** 组件数据 */
     data?:JSON

}

interface CMD{
       dom?:HTMLElement,
       cmd:string,
       txt:string  
}



/**
 * 组件数据和dom结构 \
 * 非 循环内的数据  全部在同一个 fork下 ,不对同个fork内的数据建立 children 进行父子结构分级
 *    循环内的数据  每个dom 都会建立一个children 进行父子分级
*/
interface FORK{
      
      /**  true: 循环构造体, false:普通dom  */
      arrF:boolean,
      /** 父fork */
      pFork:FORK|null,
      /** 分支的key  */
      key?:string,
      /** 分支的数据 */
      data:any,
      //当 arrF = false 时 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      /** dom自身 , 循环中初始不存在 */
      self?:HTMLElement
      /** 行内指令 e-xxx (若有) */
      cmd?:Array<CMD>,
      /** 子fork */
      children:Array<FORK> 
      /** 文本内容 (拼接 ,若有) */
      txt?:string|Array<string>,

      //当 arrF = true    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      /** dom名称 */
      name?:string,
      /** 行内属性  若有  偶:key,基:value  */
      attrs?:Array<string>,

}

/** 行内指令 */
const ORDER=['e-evt','e-attr', 'e-style' ,'e-show' ,'e-input' ,'e-change','e-html','e-text','e-filter','e-component' ];

/** 行内 */
const OL=ORDER.length;

/**
 * 获取 fork
 * @param dom   
 * @param pFork    父fork
 * @param arrF     是否处于循环中
 * @param name     nodeName
 * @returns 
 */
const GetFork=( dom:HTMLElement,pFork:FORK|null,arrF:boolean,name:string):FORK=>{
    const u=undefined;
    let attrs:any;
    let txtArr:any;
    let self:any;
         if(arrF===true){
                // 获取attr
                // 从页面删除 
                DelDom(dom);
              let arr=dom.attributes;
                  if(arr){
                      let i=0,l=arr.length;
                          if(l>0){
                             let d:any;
                             attrs=[];
                             while(i<l){
                                d=arr[i];
                                attrs.push(d.name,d.value);
                                i++;
                             }
                          }
                  }
                // console.log( `arrF = true   ${name} ` );
         }else{
                self=dom;
         }
         if(name==='#text'){
            let str=dom.textContent;
                if(str!==null){
                        str=str.trim();
                        if(str!==''){
                                console.log('解析判断文本')
                                if(str.indexOf('{{')>-1){
                                    //解析 
                                    txtArr=str;
                                }else if(arrF!==false){  // 普通文本, 非循环中
                                    txtArr=str;
                                }else{
                                    //@ts-ignore   该返回值本身就不会被使用 , 因此不会产生错误
                                    return
                                }
                        }else{
                                DelDom(dom);
                                //@ts-ignore   该返回值本身就不会被使用 , 因此不会产生错误
                                return   
                        }
                }
         };

    const fork:FORK={
          arrF:arrF,
          pFork:pFork,
          self:self,
          children:[],
          txt:txtArr,
          name:name,
          attrs: attrs
    }

       if(pFork!==null)pFork.children.push(fork);
       
    return fork;
}

/**
 * 将 childNodes 转换为Array对象
 * @param nodes childNodes
 */
const GetNodes=(dom:HTMLElement )=>{
       let nodes=dom.childNodes;
       let arr:any=[]
           if(nodes){ 
                let i=0,l=nodes.length;
                
                    while(i<l){
                        arr[i]=nodes[i];
                        i++;
                    }
           };
           return arr;
}

/**
 *  循环遍历dom 生成数据结构 
 * @param fork   父fork
 * @param nodes  子节点
 * @param arrF   true:处于数组循环中, false:normal
 * @param app    Eng instance
 */
const DomLoop=( pFork:FORK|null , nodes:Array<HTMLElement> , arrF:boolean ,app:Eng|null )=>{
      const u=undefined;
      let i=0,l=nodes.length;
      let ns=0,str='';
      let fork:FORK|null;   //当前的fork
           while(i<l){
                     fork=pFork;  
               const dom=nodes[i];
               const name=dom.nodeName;
                    //  if(arrF)console.log(`nodeName = ${name}`)
                     if(name==='#comment'){                     // 删除注释
                            DelDom(dom);
                     }else if(name==='#text'){                  // 纯文本 innerText
                            GetFork(dom,pFork,arrF,name);
                     }else if(dom.getAttribute('e-stop')===null){  // e-stop不再向下执行

                        let attr=dom.getAttribute('e-for'),f=true;

                            // e-for
                            if(attr!==null){
                                    f=false;                      // 进入循环
                                    attr=attr.trim();
                                    dom.removeAttribute('e-for');
                                    fork = GetFork( dom , pFork , true , name ); 
                                    fork.key=attr;                // key=='' 的情况也算成立 , 否则会造成整体错误 (若开发者不注意)
                                    
                                    // debugger
                            }else if(arrF){
                                    // 循环中的所有 子元素 严格分级 (建立父子结构, 不保存在同一个 fork下  ), 
                                    fork=GetFork( dom , pFork , true , name ); 
                            };

                            // e-fork    (注: 和 e-for 互斥 ,  e-for优先级最高   )
                            if(f){
                                    attr=dom.getAttribute('e-fork');
                                    if(attr!==null){
                                            
                                            attr = attr.trim();
                                            dom.removeAttribute('e-for');
                                            fork = GetFork( dom , pFork , arrF , name ) 
                                            fork.key=attr;
                                            
                                    }else if(fork===null){
                                            
                                            // 必须创建拥有一个根 fork !!!!!
                                            fork = GetFork( dom , pFork , arrF , name ) 
                                            if(app!==null)app.fork=fork;

                                    }
                            };

                            //普通行内属性 
                            if(fork!==null){
                                    ns=0;
                                    while(ns<OL){
                                        let cmd=ORDER[ns];            // e-xxx
                                        let attr=dom.getAttribute(cmd);
                                                if(attr!==null){
                                                    dom.removeAttribute(cmd);
                                                    attr=attr.trim();
                                                    if(attr!==''){
                                                        if(fork.cmd===u)fork.cmd=[];
                                                        fork.cmd.push( {dom:arrF?u:dom, cmd:cmd , txt:attr} )
                                                    };
                                                }
                                            ns++
                                    };
                                    let nodes=GetNodes(dom);
                                        if(nodes.length>0)DomLoop( fork , nodes , !f||arrF,null );
                            };   
                            
                     };

                     i++;
           };

}

/**
 * 分析等号数据
 * @param txt 
 */
const AnalyzeEqualSignData=(txt:string)=>{
    let arr=txt.split(';')
    let i=0,l=arr.length,s='';
    let drr:string[][]=[];
        while(i<l){
                 s=arr[i].trim();
             let n=s.indexOf('='),l=s.length;
                 if(n>-1&&n+1!==l){      // 排除  ''||  '=' || 'xxx=' 的情况
                    drr.push( [s.slice(0,n).trim() , s.slice(n+1,l).trim() ] )
                 }
            i++;
        }
        return drr;
}



/**
 * 处理行内指令
 */
const cmdHandle={
       'e-attr':( dom:HTMLElement , txt:string , data:any )=>{
           const drr=AnalyzeEqualSignData(txt);
           const l=drr.length;
           const vrr:any=[];
             let i=0;
                 while(i<l){
                    let d=drr[i];

                      debugger
                    i++
                 }
                 debugger
       },
       'e-style':(dom:HTMLElement , txt:string , data:any )=>{
          debugger
       }
}

/**
 * 解析处理fork   
 * @param fork 
 * @param data  当前fork数据
 * @param root  根fork
 */
const ForkHandle=( fork:FORK , data:JSON , root:FORK )=>{
     const u=undefined;
     const arrF=fork.arrF;
     const cmd=fork.cmd;
       let dom:HTMLElement;
       let key=fork.key;
       let D:any;                // 当前作用域数据
           if(key!==u){
               D=data[key];
               if(D===u)return;  //  fork 分支基本类型为 {}||[] 

              
           }else{
               D=data;
           }    
           fork.data=data;

           if(arrF){
               //循环对象需要手动创建 
               debugger
               dom=document.createElement('div');
               // fork.pFork.self.appendChild(dom);

           }else{
               dom=fork.self as HTMLElement;
           }
           // 行内指令
           if(cmd!==u){
               let i=0,l=cmd.length,k='';
                   while(i<l){
                      let d=cmd[i];
                      let f=cmdHandle[d.cmd]
                          debugger
                          if(f)f(arrF?dom:d.dom,d.txt ,D);     //arrF=> true: 分级新创建的dom 
                          i++;
                   }
           }

           //

           debugger
}

export default class Eng {
     cfg:CFG;
     el:HTMLElement;
     fork:FORK;
     data:any;
     /**
      * 
      * @param cfg 
      * @returns 
      */
     constructor(cfg:CFG){
            const t=this;
            let el=cfg.el;
            let dom;
                if(typeof(el)==='string'){
                    dom=document.getElementById(el);
                    if(dom){
                        this.el=dom; 
                    }else{
                        console.error(` 获取dom为空   id = ${el} `)
                        return;
                    }
                }
                t.cfg=cfg;

                DomLoop( null,[dom],false ,this);

                t.data= GetType(cfg.data)===2?cfg.data:{};

                ForkHandle( t.fork , t.data , t.fork )

              console.log(t.fork);
     };
     
     
}





























